# -*- coding: utf-8 -*-

import os  # 导入操作系统接口模块
import click  # 导入命令行工具库

# 兼容Python2和Python3的文件未找到异常
try:
    FileNotFoundError  # 检查Python3中是否存在此异常
except NameError:
    # Python2兼容方案
    FileNotFoundError = IOError  # 将IOError作为文件未找到异常

TEST_CMD_HELP = '运行为蓝图定义的测试。额外参数将传递给测试运行器。'  # 测试命令的帮助文本

APPS_FOLDER = 'apps'  # 蓝图应用的默认存储目录


@click.command('new-app', help='创建一个新的蓝图应用')  # 定义new-app命令
@click.argument('name', required=False)  # 可选的应用名称参数
@click.option(
    '-t', '--with-templates',  # 模板创建选项
    default=False, is_flag=True, show_default=True,  # 默认关闭/标志选项/显示默认值
    help='为蓝图创建模板文件夹')  # 选项帮助文本
def new_app(name, with_templates):
    """处理项目中蓝图应用的命令"""

    # 如果未提供名称则交互式获取
    if name is None:
        name = input('请输入新应用名称: ')  # 用户输入应用名称

        if len(name) == 0:  # 空名称检查
            print("名称不能为空")
            exit(1)

    # 检测项目依赖文件
    try:
        try:
            # 尝试读取拆分后的依赖文件
            requirements = open('requirements/common.txt').read().lower()
        except FileNotFoundError:
            # 回退到主依赖文件
            requirements = open('requirements.txt').read().lower()
    except FileNotFoundError:
        # 无依赖文件的情况
        requirements = ''

    # 创建应用目录结构
    apps_folder = os.path.abspath(APPS_FOLDER)  # 获取绝对路径
    path_name = os.path.normpath(name).replace(" ", "_").lower()  # 规范化路径名称
    app_path = os.path.join(apps_folder, path_name)  # 拼接完整应用路径

    # 检查应用是否已存在
    if os.path.exists(app_path):
        print(f'{app_path} 已存在，无法创建')
        exit()

    os.mkdir(app_path)  # 创建应用目录

    # 可选创建模板目录
    if with_templates:
        os.makedirs(os.path.join(app_path, 'templates', path_name))  # 创建嵌套模板目录

    # 创建基础文件
    with open(os.path.join(app_path, '__init__.py'), 'w') as fs:
        fs.write("from .views import app")  # 初始化蓝图应用

    # 根据依赖创建模型文件
    with open(os.path.join(app_path, 'models.py'), 'w') as fs:
        if 'flask-sqlalchemy' in requirements:
            fs.write("from extensions import db\n\n")  # SQLAlchemy支持
        if 'flask-mongoengine' in requirements:
            fs.write("from extensions import nosql\n\n")  # MongoDB支持

    # 如果使用WTForms则创建表单文件
    if 'flask-wtf' in requirements:
        with open(os.path.join(app_path, 'forms.py'), 'w') as fs:
            fs.write('from flask_wtf import FlaskForm\n\n')

    # 创建视图文件（蓝图核心）
    with open(os.path.join(app_path, 'views.py'), 'w') as fs:
        fs.write(
            "# 即使不需要传统视图也保留此文件\n"
            "# 它包含蓝图应用实例\n"
            "from flask import Blueprint\n"
            "from flask import render_template, flash, redirect, url_for\n\n"
            f"app = Blueprint('{name}', __name__, template_folder='templates')\n\n"
        )

    print(
        f'应用已创建在 {APPS_FOLDER} 目录下。\n'
        f'请记得在配置文件的 BLUEPRINTS 中添加此应用。'
    )


@click.command('test', context_settings=dict(
    ignore_unknown_options=True,  # 允许额外参数
    allow_extra_args=True,  # 接受未知选项
), help=TEST_CMD_HELP)  # 定义测试命令
@click.option('-f', '--failfast', default=False, is_flag=True, help='测试失败时立即停止')  # 快速失败选项
@click.option('-v', '--verbosity', type=int, default=1, help='测试输出详细程度 [0|1|2]')  # 输出详细级别
@click.option('-w', '--warnings', default=None, help='警告处理方式 [default|always]')  # 警告控制选项
def test_cmd(failfast, verbosity, warnings):
    """运行项目测试套件"""

    import sys
    import glob
    import unittest

    # 路径处理快捷方式
    exists = os.path.exists
    isdir = os.path.isdir
    join = os.path.join

    project_path = os.path.abspath(os.path.dirname('.'))  # 获取项目根目录
    sys.path.insert(0, project_path)  # 添加项目路径到PYTHONPATH

    # 添加蓝图应用到模块搜索路径
    if exists(APPS_FOLDER):
        sys.path.insert(0, join(APPS_FOLDER))

    loader = unittest.TestLoader()  # 创建测试加载器
    all_tests = []  # 存储所有测试用例

    # 收集蓝图应用中的测试
    if exists(APPS_FOLDER):
        for path in glob.glob(f'{APPS_FOLDER}/*'):  # 遍历所有应用
            if isdir(path):
                tests_dir = join(path, 'tests')

                # 检查不同测试文件结构
                if exists(join(path, 'tests.py')):
                    all_tests.append(loader.discover(path, 'tests.py'))
                elif exists(tests_dir):
                    all_tests.append(loader.discover(tests_dir, pattern='test*.py'))

    # 收集项目级测试
    if exists('tests') and isdir('tests'):
        all_tests.append(loader.discover('tests', pattern='test*.py'))
    elif exists('tests.py'):
        all_tests.append(loader.discover('.', pattern='tests.py'))

    # 运行测试套件
    test_suite = unittest.TestSuite(all_tests)  # 组合所有测试
    unittest.TextTestRunner(
        warnings=warnings,  # 警告设置
        failfast=failfast,  # 快速失败设置
        verbosity=verbosity  # 输出详细级别
    ).run(test_suite)  # 执行测试